Write your own ASM key gen, by Lord Soth
=--------------------------------------=

Hiya guys, it's Lord Soth here.
In this short text file I will try to describe how to write a serial number generator for an application you already reversed (no point in writing 1 for an APP you have'nt reversed yet, is there?)
I'm assuming here you already know everything there is to know about how the target program is protected and how it calculates it's serial number.
Just a side matter in this whole cracking experience is this. Did you ever stop to think if it would be worth it to even try to reverse the calc routine ?
Everybody knows there are plenty of ways to crack a program. You don't necessarily have to make a key gen, you can 'fix' the comparison routine to let you register all the time, or if there is no registeration dialog, you can remove the protections 1 by 1, etc etc...
There enough ways, but some might not be good for certain applications. I have found that for example, NewGrabber 2.1.19 is nearly impossible to crack if you try to 'fix' the comparison routine. In this app's case, the program uses that same comparison routine to compare other bytes of data during the program runtime, and after I patched it, I found that it can't do it's main function, which is to DL news!!!
In these complex cases we'll try to write a serial key gen. A serial key gen is a perfect solution anyhow because it will give you full access to the program and will register your name on it hehe
After we settled this little issue, lets go down to business.

Now, a few remarks on the calculation.
Sometimes, you reverse the calc routine and write down the stages (that's how I do it hehe) of the calculation, then you wanna go and write your own code that will do the same.
Basically the code is pretty much the same, but not quite. There might be several changes to the code, since you don't work with the same memory structure as the program, etc, etc...
So you might wanna write it all over again, as simple as possible.
Now some things to remember:

1> Always make sure to start calculating with the same starting values as the prog does. (doh 	     this might seem trivial, but believe me, if u don't pay attention, u can spend hours on trying    to figure out why your damn routine does'nt calculate well ).. whew :)

2) Always make sure you work with the same kind of variables. Meaning, if the program uses a 32      bit register to do a certain calc, be sure to give it the same starting values, and use it        exactly as the program does.

3) Pay special attention to signed register values. Sometimes the programs use a signed 32 or 16     bit value for the calculation. If this is the case, you MUST use the same 'type' of variable,     because otherwise some usernames (a big percentage), might give you a weird serial.
   Just as a note, the ASM mnemonics that are usually used for signed variables are MOVSX and        such (note that in the case of MOVSX, you must write your code in 386+ mode, cause the            assembler won't let you assemble this instruction without it).

4) Notice that the program uses certain chars out of the user name. Some progs don't make use of     all the chars the user enters.

5) Always remember to recreate the user name like the prog does. Most programs modify the user       name a little bit. They either make it all lower-case , or upper-case, might put a string         after it, so that if the username is small (1 or 2 chars for example), the program has more to    work with. Very imperative that the REAL user name will be recreated, other wise u got nothing    to work by hehe
   This might require some more reversing, but not normally.

OK, enough blabbering about this , now lets write the gen
---------------------------------------------------------

Ok , when we go down to writing this thing, we have to ask what kind of things it is supposed to do, other than the recreation of the username, and the calculation.
Typical things you would need is a routine that actually gets the username from the keyboard, and puts it in memory. Now, this ain't Windoze, so you can't use a fancy API called GetWindowTextA or something like that.
You gotta make it yourself. I bet there are quite a few ways to do this, I'll name 1 that I used, and how it works, and why I used it.
First, I used it because it's quite easy to code, and because it's sufficient for almost all kinds of usernames. It takes account of ALL keystrokes, and that could be an advantage or a disadvantage as well, since the APIs normally used don't consider weird stuff like function keys and such.
However, this will do it for us.
You CAN write your serial generator in ASM and for Win32 platform, with a GUI and use API's just like most Windoze C programs, and for the most part its pretty easy too, but the function the key generator has to do is so basic, that it would make sense to write it in a very simple DOS based GUI hehe
So, what do we do?
First, you have to put aside some memory for strings to be displayed.
General stuff like :

"ACDC32 version XXX serial key generator" (ACDC is just an example however)
"Enter your user name: "
"Your serial number is... blah blah", as a finishing message.

This is basically the normal stuff you'll need. Then again, you can throw in some other goodies, hehe, like say, a string that gives an error if you don't enter any chars, or stuff like that.
No matter how many strings and messages you'll require, it is best to always think about what you will need.
Then comes a moment you need to put aside memory for some variables for the calculations.
These could be in the form of memory locations, either signed or not (again make sure when you deal with singed values to use the correct mnemonics in the calculation).
I try to use the least amount of memory for these things. What I usually do is to put aside a long buffer of 256 bytes. I usaully read the user name into this buffer, then I progress the pointer to be right AFTER the user name, then I recreate the user name the calc routine needs and put it right after it.
Of course, you can also divide these segments of memory, and give different names to their starting address, it's just a matter of convenience.
Define all kinds of strings you'll need to remake the user name, or define a procedure that makes it. A good example is a PROC that transforms letters to uppercase or lowercase.
In any case, whatever your way of choice, have enough memory for these operations, this is especially important if you play around with pointers.
Now, after you have set up all your intended data structures, like strings, variables, values, constants, whatever, you can start coding the real thing.

Coding the gen
==============
Now, here we go down to business. You typically start with a routine that maybe clears the screen, puts up a sentence telling the user to enter a registration user name.
Now, a good hint on making a key capturing routine, which is also good enough to NOT store in memory weird chars like DEL or ESC, is to use interrupt 16.
The get keystroke interrupt gets a scan code and an ASCII value. Use the scan code to check if the user pressed 1 of the 'special' keys, such as Enter , in which you'll need to branch outa the input routine. Another good example is the DEL char.
Normally, you'd want it to perform just as usual. Well, how do you code usual ?
Quite simple I guess hehe
You need a pointer to a memory location to store your username, then you need an indirect index like say BX, so you can increase it whenever a key is pressed.
If a DEL key is pressed (scan code 10 i think), you should NOT increase the indirect pointer, you need to decrease it, and then write a space on the screen where there was the last char.
Note that you gotta take into account that if your pointer (i.e. BX), will go lower than 0 which is the base value for the memory structure , you might have undesirable effects, and even more, you'll see you can go back and delete everything on the screen. So make sure you check that when BX is 0, you can't decrease it further.
The exact coding is up to you of course, I won't type everything for ya , ya know :)

OK, assuming you lived through this tedious process (hehe not that tedious for all you windoze programmers..), you now recreate the real user name.
Just use the algorythm the program used, it's pretty simple most of the times, and you don't even have to copy their code, you can manufacture it efficiently on your own.
Remember, ALWAYS think in advance when writing in Assembly, because there is no compiler to save your neck if you define your data structures wrongly.
You MUST think about where you're gonna put all these names and numbers, so plan ahead.
If you see you need some more space, you can always redefine more. I wonder how many times you might get an exception because the gen wrote to a memory location it wasn't supposed to hehehe
Ok, enough of this :)

Now, assuming you recreated the user name correctly, you can go on to calculation. Note that you must check all the possibilities the program recreates the real username, otherwise your gen will not be complete.
Let me give an example:

Lets take NewsGrabber 2.1.19, which I recently cracked, just for fun.
I found out that it is very hard to 'fix' the comparison routine, so I went after the calculation routine of the serial. I could have gone after the nag screen and 50 uses the shareware program offers, but I wanted to calculate the serial because on recent version it seemed like it's a hard to reverse situation. I was DEAD wrong, it was very easy.
What the program does actually, is take the user name entered, then it copies it in memory several times, just to throw ya off a little.
After a while, you stumble upon a string which is used to calculate the serial.
This string is composed of the following :

The chars QW, followed by the user name (as it was entered, not uppercase or lowercase changes), then followed by the chars AW, the followed again by the user name, and then the programmers put an extra string, just following the 2nd user name, which is "Stormingthepalace"
Why did they put it there? Why does any of them use other FIXED chars in the calcualtion?
It's because if the user decides to enter a very short serial, such as 1 letter, the program won't generate a small easily calculated number. After all, they did want to protect it hehe
What's the use if any one on the net could enter 1 char and guess out the code?
So the string looks like this (I used Lord Soth of course):

QWLord SothAWLord SothStormingthepalace

Then the program reads the 4 first chars, makes it's calculation, writes the 3 digit number it derives (will not give anymore hints on this program), then goes to the next 4 chars.
It does this 4 times total, so it uses 16 chars MAX.
Now you see why it is very important to know EXACTLY how the program recreates the user name for calculation.
With that in mind, we go on to the main function of this program, which is to CALCULATE the damn serial number.

Here I can't give you much help. You have to reproduce the same exact calculation the real program does, and sometimes you can copy some lines of code from the master program, just to make your life easier.
You will not always do this , because the structure of your program is very different from the real program's, but it should be very closely related.
Of course, you write the result, or results, to your memory block, and not push it on the stack or store it like the real program does hehehe

Once calculation is over, you can go on to printing your name, and anything else you'd like to do before the program exits back to the OS.
If no chars have been entered, you must be prepared to make it so the gen recognizes this situation.
Other conditions might arise if you can come up with, I could barely come up with reasonable ones except that 1 :)

A few words about the code itself
=================================
Normally, i suggest using either the Compact or Small memory models, becuase they are the most compatible with this kind of small utilities.
I also suggest working in 32 bit if possible. I don't suggest going to protected mode just to make a serial calculation, but on most cases, you'll have to use 32 bit registers and ASM instructions, so you must be prepared to use them in your code.
Just a quick note on this, when you put the .386 directive, bear something in mind.
When I first coded my 1st gen, I had some memory issues after assembling and linking. It seemed the pointers to string and memory locations in general , were'nt pointing to the right places!
I found out that it's because the .386 directive was put BEFORE the data declaration part of the program.
I changed it, I put is right before the real code begins. Of course, if you're using a newer version of TASM or MASM you might get "No program entry code", this means you need the .STARTUP and .EXIT directives.
The .STARTUP is put right after the .code directive, and the .EXIT is right before the final END (just a reminder).
This creates a little piece of code at the beginning, before your program starts, nothing to worry about. After the .STARTUP, you can safely put the .386C directive.
This will tell the assembler you want NON protected mode 386 operations.
Finally, there is a weird anomaly I found, not sure if it's the way I'm assembling or not, but if your PROCs are declared before your actual code, it'll start executing by that order, meaning, executing the procedures.
I always put all PROCs after the main program module ends.
What else?
Well, if you intend to use any DOS or BIOS service, only change the neccesary registers for entry. Don't zero out other parts if you don't need and stuff like that.
I found out that when you try reading the cursor position for example, if you put a 0 in AL (or was it AH?? hehe), the program hangs.
Kinda weird eh? never thought DOS would act like that, even though it only uses 1 value.
Ahh well, you can't have a perfect OS, can't ya? I guess that road is way too long.
BTW, speaking of OSes, any of you guys who uses Windoze can safely go to Linux :)

Just a reminder, that Windoze uses DOS interrupts in it's Kernel routines as well, what a bummer. We thought the Micro$oft boys could bring us a good OS, we were wrong, and they are basing all their other apps and OSes on this same approach, so it won't get any better :(

Just wanted to shine a little light on the grim and ugly truth.
But I was distracted hehe

Final notes. NONE!
Go write the dame serial generator already, stop reading and get coding, the best way to learn is to write 1 yourself, and see the result, and try to fix the bugs. ALWAYS assume there will be bugs :)

Ok this is it for now, I'll cya all later I guess.
Have fun reversing and coding.

By the way, the Immortal Descendants DataBase is supposed to have a skeleton ASM generic source code for a serial generator. You only need to enter a few modifications to it, and you can use it, just gimme credit if you do :)
It already has a way to get the user info , and is fully debugged , so have no fear. It also exits if no chars have been entered (important feature, if you slept during this "lecture" , then you should go back and read that part! hehe)
Other remarks are there to help you out if you need it, they more or less explain what should be put and where, and what to change.

Well, this is it for real.
Have fun and goodbye.

Lord Soth

Immortal Descendants, all rights reserved.













